﻿#pragma once

#include "Asset/Asset.h"
#include "Render/Image.h"

#include <stb_image.h>

class CORE_API Texture : public Asset
{
public:
    Texture() = default;
    Texture(
        const std::string &path,
        uint32_t target = GL_TEXTURE_2D,
        uint32_t internalFormat = GL_RGBA,
        uint32_t format = GL_RGBA,
        uint32_t type = GL_UNSIGNED_BYTE,
        bool generateMipMap = true,
        int32_t maxLod = 1000);
    ~Texture();

    void Generate();
    void Generate(
        uint32_t target,
        uint32_t internalFormat,
        uint32_t format,
        uint32_t type,
        bool generateMipMap,
        int32_t maxLod = 1000);

    bool IsValid() const { return m_textureID != 0; }

    void Bind() const;
    void BindToSlot(unsigned int slot = 0) const;
    void Unbind() const;

    void Allocate(int width, int height);

    void Buffer2DRGBAData(const Image& image);
    void BufferCubeMapData(std::array<Image, 6> &data);
    void LoadTexture2D(const std::string &path);
    void LoadTextureCubeMap(const std::string &path);

    void SetWrapParam(GLenum s = GL_CLAMP_TO_EDGE, GLenum t = GL_CLAMP_TO_EDGE);
    void SetFilterParam(GLenum min = GL_LINEAR, GLenum mag = GL_LINEAR);

    inline uint32_t GetID() const { return m_textureID; }
    inline int GetWidth() const { return m_width; }
    inline int GetHeight() const { return m_height; }

    Texture(const Texture &) = delete;
    Texture(Texture &) = delete;
    Texture(Texture &&) noexcept = delete;
    Texture &operator=(Texture &) = delete;
    Texture &operator=(Texture &&) noexcept = delete;

protected:
    GLuint m_textureID = 0;
    int m_width, m_height, m_channels;
    uint32_t m_target;
    uint32_t m_internalFormat;
    uint32_t m_format;
    uint32_t m_type;
    bool m_generateMipMap;
    int32_t m_maxLod;
};